package com.example.demo.auth

import com.auth0.jwt.JWT
import com.auth0.jwt.JWTVerifier
import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.interfaces.DecodedJWT
import com.example.demo.service.sso.EasyRbacService
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.method.HandlerMethod
import javax.servlet.http.HttpServletRequest

@Component
class AdminAuthHandler(@Value("\${jwt.easy-rbac-key}") val jwtKey: String,private val ssoService: EasyRbacService) : IAuthHandler {

    override fun match(request: HttpServletRequest?, handlerImpl: HandlerMethod?): Boolean {
        val authorizationHeader = AuthorizationHeader.newAuthorizationHeader(request!!)
        return authorizationHeader?.schema == "ER"
    }

    private var require: JWTVerifier = JWT.require(Algorithm.HMAC256(jwtKey)).build()

    override fun verifyUser(request: HttpServletRequest, handlerImpl: HandlerMethod): AuthResult {
        val authHeaderStr = request.getHeader("Authorization")
        val authHeader = authHeaderStr.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
        if (authHeader.size < 2) {
            val authResult = AuthResult.newUnAuthResult("Authorization Header 非法")
            return authResult
        }
        val token = authHeader[1]

        val jwtInfo: DecodedJWT
        try {
            jwtInfo = require.verify(token)
        } catch (e: Exception) {
            val authResult = AuthResult()
            authResult.isVerify = false
            authResult.message = e.message
            return authResult
        }

        val authResult = AuthResult()
        authResult.isVerify = true
        val baseUserInfo = AdminUserInfo()
        baseUserInfo.userId = jwtInfo.getClaim("userId").asLong()
        baseUserInfo.userType = AuthType.Admin
        baseUserInfo.name = jwtInfo.getClaim("name").asString()
        baseUserInfo.token = jwtInfo.getClaim("token").asString()
        authResult.userInfo = baseUserInfo

        if(!verifyPermission(handlerImpl,baseUserInfo)){
            val authResult = AuthResult()
            authResult.httpStatus = HttpStatus.FORBIDDEN
            authResult.message = "No Permission"
            return authResult
        }
        request.setAttribute(AuthHelper.AUTH_KEY_USER_INFO, baseUserInfo)


        return authResult
    }

    private fun verifyPermission(handlerImpl: HandlerMethod,userInfo: AdminUserInfo):Boolean{
        val authAnnonation = handlerImpl.getMethodAnnotation(Auth::class.java)

        return authAnnonation.isAllowAnonymous || ssoService.hasPermission(userInfo.token, authAnnonation.resourceCode)
    }
}